<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="fWWI9" id="fWWI9"><span data-lake-id="udf119355" id="udf119355">典型回答</span></h1>
  <p data-lake-id="u0fb4f093" id="u0fb4f093"><br></p>
  <p data-lake-id="u9c636f68" id="u9c636f68"><span data-lake-id="u929e3712" id="u929e3712">Kafka 中常见的选举过程有以下几种：</span></p>
  <p data-lake-id="u266d2d58" id="u266d2d58"><span data-lake-id="ubfdb1545" id="ubfdb1545">​</span><br></p>
  <p data-lake-id="u4a182754" id="u4a182754"><strong><span data-lake-id="u8aea9dae" id="u8aea9dae">Partition Leader 选举</span></strong></p>
  <p data-lake-id="u4c55fe9d" id="u4c55fe9d"><strong><span data-lake-id="u21541e04" id="u21541e04">​</span></strong><br></p>
  <p data-lake-id="u453da7ef" id="u453da7ef"><span data-lake-id="ufc456b42" id="ufc456b42">Kafka 中的每个 Partition 都有一个 Leader，负责处理该 Partition 的读写请求。在正常情况下，Leader 和 ISR 集合中的所有副本保持同步，Leader 接收到的消息也会被 ISR 集合中的副本所接收。当 leader 副本宕机或者无法正常工作时，需要选举新的 leader 副本来接管分区的工作。</span></p>
  <p data-lake-id="u405aa458" id="u405aa458"><span data-lake-id="udf79ff2f" id="udf79ff2f" class="lake-fontsize-12" style="color: rgb(55, 65, 81); background-color: rgb(247, 247, 248)">​</span><br></p>
  <p data-lake-id="u965d6431" id="u965d6431"><span data-lake-id="ue79dae90" id="ue79dae90">Leader 选举的过程如下：</span></p>
  <ul list="u99e4089f">
   <li fid="ua7cb2e91" data-lake-id="ubcf99b53" id="ubcf99b53"><span data-lake-id="uf7debb43" id="uf7debb43">每个参与选举的副本会尝试向 ZooKeeper 上写入一个临时节点，表示它们正在参与 Leader 选举；</span></li>
   <li fid="ua7cb2e91" data-lake-id="u873673a6" id="u873673a6"><span data-lake-id="u52f650c1" id="u52f650c1">所有写入成功的副本会在 ZooKeeper 上创建一个序列号节点，并将自己的节点序列号写入该节点；</span></li>
   <li fid="ua7cb2e91" data-lake-id="u1c7b7e3b" id="u1c7b7e3b"><span data-lake-id="u4e874b81" id="u4e874b81">节点序列号最小的副本会被选为新的 Leader，并将自己的节点名称写入 ZooKeeper 上的 /broker/.../leader 节点中。</span></li>
  </ul>
  <p data-lake-id="u16f0e8d4" id="u16f0e8d4"><br></p>
  <p data-lake-id="u528ed60a" id="u528ed60a"><strong><span data-lake-id="uf48ce79b" id="uf48ce79b">Controller 选举</span></strong></p>
  <p data-lake-id="u19e6e66f" id="u19e6e66f"><span data-lake-id="u1a554167" id="u1a554167">​</span><br></p>
  <p data-lake-id="u66d78266" id="u66d78266"><span data-lake-id="uf77b3f0e" id="uf77b3f0e">Kafka 集群中只能有一个 Controller 节点，用于管理分区的副本分配、leader 选举等任务。当一个Broker变成Controller后，会在Zookeeper的/controller节点 中记录下来。然后其他的Broker会实时监听这个节点，主要就是避免当这个controller宕机的话，就需要进行重新选举。</span></p>
  <p data-lake-id="u64d79e31" id="u64d79e31"><br></p>
  <p data-lake-id="u487c5f31" id="u487c5f31"><span data-lake-id="ua6fb5bd8" id="ua6fb5bd8">Controller选举的过程如下：</span></p>
  <ul list="uee61a2fe">
   <li fid="u3146fdbd" data-lake-id="u34574897" id="u34574897"><span data-lake-id="ubb897af8" id="ubb897af8">所有可用的 Broker 向 ZooKeeper 注册自己的 ID，并监听 ZooKeeper 中 /controller 节点的变化。</span></li>
   <li fid="u3146fdbd" data-lake-id="u7ddc9170" id="u7ddc9170"><span data-lake-id="ub79457ae" id="ub79457ae">当 Controller 节点出现故障时，ZooKeeper 会删除 /controller 节点，这时所有的 Broker 都会监听到该事件，并开始争夺 Controller 的位置。</span></li>
   <li fid="u3146fdbd" data-lake-id="uf8470edd" id="uf8470edd"><span data-lake-id="u520cae15" id="u520cae15">为了避免出现多个 Broker 同时竞选 Controller 的情况，Kafka 设计了一种基于 ZooKeeper 的 Master-Slave 机制，其中一个 Broker 成为 Master，其它 Broker 成为 Slave。Master 负责选举 Controller，并将选举结果写入 ZooKeeper 中，而 Slave 则监听 /controller 节点的变化，一旦发现 Master 发生故障，则开始争夺 Master 的位置。</span></li>
   <li fid="u3146fdbd" data-lake-id="u607902d2" id="u607902d2"><span data-lake-id="u98e14063" id="u98e14063">当一个 Broker 发现 Controller 失效时，它会向 ZooKeeper 写入自己的 ID，并尝试竞选 Controller 的位置。如果他创建临时节点成功，则该 Broker 成为新的 Controller，并将选举结果写入 ZooKeeper 中。</span></li>
   <li fid="u3146fdbd" data-lake-id="uf542ecfa" id="uf542ecfa"><span data-lake-id="uc5d5e265" id="uc5d5e265">其它的 Broker 会监听到 ZooKeeper 中 /controller 节点的变化，一旦发现选举结果发生变化，则更新自己的元数据信息，然后与新的 Controller 建立连接，进行后续的操作。</span></li>
  </ul>
  <p data-lake-id="ua491e63e" id="ua491e63e"><span data-lake-id="uf058885e" id="uf058885e">​</span><br></p>
  <h1 data-lake-id="ZaLP3" id="ZaLP3"><span data-lake-id="ub7b44feb" id="ub7b44feb">扩展知识</span></h1>
  <p data-lake-id="u18624489" id="u18624489"><br></p>
  <h2 data-lake-id="VAd3z" id="VAd3z"><span data-lake-id="uf2c0adfb" id="uf2c0adfb">kafka选举中，为什么节点序列号最小的副本会被选为新的 Leader</span></h2>
  <p data-lake-id="u43115ce7" id="u43115ce7"><span data-lake-id="ub593c920" id="ub593c920">​</span><br></p>
  <p data-lake-id="u8619dc22" id="u8619dc22"><span data-lake-id="uccdc3510" id="uccdc3510">在Kafka中，节点序列号最小的副本被选为新的Leader是因为Kafka使用了ZooKeeper作为其协调服务。在Kafka集群中，ZooKeeper负责维护集群的元数据（例如主题和分区信息）以及Brokers（Kafka服务器）的状态。</span></p>
  <p data-lake-id="u30f2e9a3" id="u30f2e9a3"><span data-lake-id="ub3f26178" id="ub3f26178">​</span><br></p>
  <p data-lake-id="ua00785b0" id="ua00785b0"><span data-lake-id="u9808f52a" id="u9808f52a">当一个Broker（副本）成为Leader候选人时，它会向ZooKeeper注册自己并申请成为该分区的Leader。在这个过程中，每个候选人都会创建一个临时的带有递增序列号的ZooKeeper节点，称为"选举竞争者（election contender）"。</span></p>
  <p data-lake-id="ub4ac532b" id="ub4ac532b"><span data-lake-id="u317bcb5f" id="u317bcb5f">​</span><br></p>
  <p data-lake-id="u8cce323d" id="u8cce323d"><span data-lake-id="ua4a507f9" id="ua4a507f9">当候选人注册完成后，它们会查询ZooKeeper并比较自己的序列号与其他候选人的序列号。Kafka采用基于递增序列号的最小值来选择新的Leader。因此，具有最小序列号的候选人将成为新的Leader，并负责处理该分区的所有读写请求。</span></p>
  <p data-lake-id="u95426b10" id="u95426b10"><span data-lake-id="u0515e1d0" id="u0515e1d0">​</span><br></p>
  <p data-lake-id="u5380303f" id="u5380303f"><span data-lake-id="u19b24c82" id="u19b24c82">通过这种方式，Kafka实现了简单而有效的Leader选举机制，确保了高可用性和数据一致性。选择序列号最小的副本作为Leader可以避免分区的不一致情况，并且能够快速地恢复正常操作，因为ZooKeeper节点序列号是唯一且递增的。</span></p>
 </body>
</html>